/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package systole.view.tabs.controllers;

import java.io.File;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

import org.jfree.ui.ExtensionFileFilter;

import systole.domain.analysis.Analysis;
import systole.domain.report.builder.ClasicReportBuilder;
import systole.domain.signals.RawSignal;
import systole.exceptions.ExceptionDAO;
import systole.ioHandling.printers.PrinterManager;
import systole.persistence.FacadeDB;
import systole.view.MainController;
import systole.view.SystoleApp;
import systole.view.messages.DialogsMessages;
import systole.view.pdfView.PdfSystoleViewer;
import systole.view.tabs.JpnlAnalysis;
import systole.view.tabs.results.background.ControllerBackground;
import systole.view.tabs.results.comments.ControllerComment;
import systole.view.tabs.results.conclusion.ControllerConclusion;
import systole.view.tabs.results.index.ControllerIndex;
import systole.view.wizard.WizardImplement;
import systole.view.wizard.analysis.WizardAnalysisImplement;
import systole.view.workers.WorkerFilter;
import systole.view.workers.WorkerOpenAnalysis;
import systole.view.workers.WorkerProcessor;
import systole.view.workers.WorkerReport;
import systole.view.workers.WorkerSlicer;

/**
 * 
 * @author jmj
 */
public class AnalysisController {

    private MainController parent;
    private JpnlAnalysis frmAnalysis = null;
    private Analysis analysis;
    private boolean isNewAnalysis = true;
    private SelectionModel selectionModel;
    private ReportModel reportModel;
    private ResultsModel resultsModel;
    private boolean waitingForClose = false;
    private boolean waitingForSave = false;
    private ControllerComment controllerComment;
    private ControllerConclusion controllerConclusion;
    private ControllerIndex controllerIndex;
    private ControllerBackground controllerBackground;

    /**
     * @param parent
     */
    public AnalysisController(MainController parent) {
        this.parent = parent;
        this.controllerComment = new ControllerComment();
        this.controllerConclusion = new ControllerConclusion();
    }

    private void initControllerContext() {
        this.selectionModel = new SelectionModel();
        this.reportModel = new ReportModel(this.analysis);
        this.resultsModel = new ResultsModel(this.analysis);
        this.frmAnalysis = new JpnlAnalysis(this);
        this.controllerIndex = new ControllerIndex(this.analysis.getPatient());
        this.controllerBackground = new ControllerBackground(this.analysis.getPatient());
    }

    /**
     * @return if the analysis can be created
     */
    public boolean createAnalysis() {

        WizardImplement wizard = new WizardAnalysisImplement(SystoleApp.getApplication().getMainFrame());
        this.analysis = (Analysis) wizard.executeWizard();

        if (this.analysis != null) {
            this.initControllerContext();
            this.startFiltering();
            return true;
        }
        return false;
    }

    /**
     * @param rawSignal 
     * @param filePath
     * @return if the analysis can be created
     */
    public boolean createAnalysis(RawSignal rawSignal, String filePath) {

        WizardImplement wizard = new WizardAnalysisImplement(SystoleApp.getApplication().getMainFrame(), rawSignal, filePath);
        this.analysis = (Analysis) wizard.executeWizard();

        if (this.analysis != null) {
            this.initControllerContext();
            this.startFiltering();
            return true;
        }
        return false;
    }

    /**
     * @param analysis
     */
    public void openAnalysis(Analysis analysis) {
        this.analysis = analysis;
        this.initControllerContext();
        this.isNewAnalysis = false;
        this.startOpenAnalysis();
    }

    /**
     * @return the frmAnalysis
     */
    public JpnlAnalysis getFrmAnalysis() {
        return frmAnalysis;
    }

    /**
     * @return the analysisModel
     */
    public Analysis getAnalysis() {
        return analysis;
    }

    /**
     * @param analysis
     *            the analysis to set
     */
    public void setAnalysis(Analysis analysis) {
        this.analysis = analysis;
    }

    /**
     * 
     */
    public void startFiltering() {
        WorkerFilter workerFilter = new WorkerFilter(this);
        workerFilter.execute();
    }

    /**
     * 
     */
    public void startSlicing() {
        WorkerSlicer swSlicer = new WorkerSlicer(this);
        swSlicer.execute();
    }

    /**
     *
     */
    public void startOpenAnalysis() {
        WorkerOpenAnalysis workerOpenAnalysis = new WorkerOpenAnalysis(this);
        workerOpenAnalysis.execute();
    }

    /**
     * 
     */
    private void startProcessing() {
        WorkerProcessor processor = new WorkerProcessor(this);
        processor.execute();
    }

    /**
     * 
     */
    private void notifyEmptyModel() {
        // quito los paneles con los graficos y muestro el mensaje para
        // seleccionar
        this.frmAnalysis.getFinalSignalPnl().showEmptyPanel();
        this.frmAnalysis.getFinalSignalPnl().revalidate();
        // quito los paneles con los graficos y muestro el mensaje para
        // seleccionar
        this.frmAnalysis.getJReportView().showEmpty();
    }

    /**
     * 
     */
    public void startReporting() {
        WorkerReport workerReport = new WorkerReport(this);
        workerReport.execute();
    }

    /**
     * @param msg
     * @param title
     * @param messageTpe
     */
    public void showMessage(String msg, String title, int messageTpe) {
        JOptionPane.showOptionDialog(this.frmAnalysis, msg, title,
                JOptionPane.CLOSED_OPTION, messageTpe, null, null, null);

    }

    /**
     * clear current selection of segments
     */
    public void clearSelection() {
        if (!this.selectionModel.isSelectionEmpty()) {
            this.selectionModel.clearSelection();
            this.notifyEmptyModel();
        }
    }

    /**
     * confirm the current selection of segments
     */
    public void confirmSelection() {

        if (this.selectionModel.isSelectionEmpty()) {
            this.showMessage("No ha seleccionado ningún segmento aún",
                    DialogsMessages.DIALOG_BOX_TITLE, JOptionPane.ERROR_MESSAGE);
            return;
        }

        if (this.selectionModel.isConfirmed()) {
            this.frmAnalysis.showFinalPnl();
            return;
        }

        this.selectionModel.confirmModel(this.analysis);
        this.startProcessing();
    }

    /**
     * export report to pdf
     */
    public void generateReport() {

        if (!this.checkSelectionModel()) {
            return;
        }

        if (this.selectionModel.isModified()) {
            if (JOptionPane.OK_OPTION != JOptionPane.showOptionDialog(this.frmAnalysis,
                    "La lista de segmentos seleccionada se ha modificado, si continúa el reporte generado "
                    + "corresponderá a la última selección confirmada", DialogsMessages.DIALOG_BOX_TITLE,
                    JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null)) {
                return;
            }
        }

        String filename = "Informe_"
                + this.analysis.getPatient().getFullName() + ".pdf";
        JFileChooser fc = new JFileChooser();
        fc.setFileFilter(new ExtensionFileFilter("pdf", "pdf"));
        fc.setSelectedFile(new File(filename));
        int returnVal = fc.showSaveDialog(this.frmAnalysis);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            File file = fc.getSelectedFile();
            ClasicReportBuilder builder = new ClasicReportBuilder();
            builder.build(this.analysis, this.reportModel.getCurrentReport(), this.resultsModel.getCurrentResults(), file);
            JOptionPane.showOptionDialog(this.frmAnalysis,
                    DialogsMessages.REPORT_GENERATED,
                    DialogsMessages.DIALOG_BOX_TITLE,
                    JOptionPane.CLOSED_OPTION,
                    JOptionPane.INFORMATION_MESSAGE, null, null, null);
        }
    }

    /**
     * print the report
     */
    public void printReport() {

        if (!this.checkSelectionModel()) {
            return;
        }

        if (this.selectionModel.isModified()) {
            if (JOptionPane.OK_OPTION != JOptionPane.showOptionDialog(this.frmAnalysis,
                    "La lista de segmentos seleccionada se ha modificado, si continúa el reporte impreso "
                    + "corresponderá a la última selección confirmada", DialogsMessages.DIALOG_BOX_TITLE,
                    JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null)) {
                return;
            }
        }

        ClasicReportBuilder builder = new ClasicReportBuilder();
        PrinterManager printer = new PrinterManager();
        try {
            printer.printReport(builder.buildToPrint(this.analysis, this.reportModel.getCurrentReport(), this.resultsModel.getCurrentResults()));
        } catch (Exception e) {
            this.showMessage("No se pudo imprimir el reporte", DialogsMessages.DIALOG_BOX_TITLE, JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * report preview
     */
    public void previewReport() {

        if (!this.checkSelectionModel()) {
            return;
        }

        if (this.selectionModel.isModified()) {
            if (JOptionPane.OK_OPTION != JOptionPane.showOptionDialog(this.frmAnalysis,
                    "La lista de segmentos seleccionada se ha modificado, si continúa el reporte visualizado "
                    + "corresponderá a la última selección confirmada", DialogsMessages.DIALOG_BOX_TITLE,
                    JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, null, null)) {
                return;
            }
        }
        ClasicReportBuilder builder = new ClasicReportBuilder();
        try {
            PdfSystoleViewer pdf = new PdfSystoleViewer(builder.buildToPrint(this.analysis, this.reportModel.getCurrentReport(), this.resultsModel.getCurrentResults()), this.analysis.toString());
            pdf.showPdf();
        } catch (Exception e) {
            this.showMessage("No se pudo realizar la previsualización del reporte", DialogsMessages.DIALOG_BOX_TITLE, JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * @return if analysis was processed
     */
    public boolean isAnalysisProcessed() {
        return (this.selectionModel.isConfirmed() && !this.selectionModel.isSelectionEmpty());
    }

    /**
     * @return selection model
     */
    public SelectionModel getSelectionModel() {
        return this.selectionModel;
    }

    /**
     * 
     */
    public void clearObjectInstances() {
        this.selectionModel.deleteObservers();
        this.reportModel.deleteObservers();
        this.resultsModel.deleteObservers();
        this.frmAnalysis.clearObjectInstance();
    }

    /**
     * @return the reportModel
     */
    public ReportModel getReportModel() {
        return reportModel;
    }

    /**
     * @return the resultsModel
     */
    public ResultsModel getResultsModel() {
        return resultsModel;
    }

    /**
     *
     * @return if analysis was edited
     */
    public boolean wasModified() {
        return ((this.isNewAnalysis) || (this.selectionModel.isDirty() || (!this.selectionModel.isConfirmed()))
                || (this.resultsModel.isDirtyModel()) || (this.reportModel.isDirtyModel()));
    }

    /**
     *
     */
    public void loadAnalysisToSave() {

        // si no hay nada seleccionado se eliminan el resto de los objetos
        // dependientes de la selección.
        if (this.selectionModel.getOriginalSegments().isEmpty()) {
            this.analysis.getSelectedSegments().clear();
            this.analysis.setReport(null);
            this.analysis.setAnalysisResult(null);
            this.selectionModel.save();
            this.resultsModel.save();
            this.reportModel.save();
            return;
        }

        this.selectionModel.save();
        this.analysis.setSelectedSegments(this.selectionModel.getSelectedSegments());

        this.resultsModel.save();
        this.analysis.setAnalysisResult(this.resultsModel.getOriginalResults());
        this.analysis.setFinalSegment(this.resultsModel.getOriginalFinalSignal());

        this.reportModel.save();
        this.analysis.setReport(this.reportModel.getOriginalReport());

    }

    /**
     *
     */
    private void save() {
        try {
            FacadeDB.getInstance().startTransaction();
            if (this.isNewAnalysis) {
                FacadeDB.getInstance().getAnalysisBroker().insert(this.analysis);
            } else {
                FacadeDB.getInstance().getAnalysisBroker().update(this.analysis);
            }
            FacadeDB.getInstance().commitTransaction();
            this.isNewAnalysis = false;
        } catch (ExceptionDAO ex) {
            FacadeDB.getInstance().rollbackTransaction();
            this.showMessage(ex.getMessage(), DialogsMessages.DIALOG_BOX_TITLE, JOptionPane.ERROR_MESSAGE);
        }
    }

    public void saveAnalysis(boolean isClosing) {

        if (!this.selectionModel.isConfirmed()) {

            String msgQuery = (this.selectionModel.isSelectionEmpty())
                    ? "La lista de segmentos seleccionada fue vaciada, ¿Desea mantenerla vacía?"
                    : "Los segmentos seleccionados no han sido confirmados, ¿Desea confirmarlos?";

            int res = JOptionPane.showOptionDialog(this.frmAnalysis,
                    msgQuery, DialogsMessages.DIALOG_BOX_TITLE,
                    JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE, null,
                    null, null);

            if (res == JOptionPane.YES_OPTION) {
                // remove all and save
                if (this.selectionModel.isSelectionEmpty()) {
                    this.analysis.getSelectedSegments().clear();
                    this.analysis.setReport(null);
                    this.analysis.setAnalysisResult(null);
                    this.loadAnalysisToSave();
                    this.save();
                    if (isClosing) {
                        this.parent.closeAnalysisAfterProcess(this.frmAnalysis);
                    }
                    return;
                }
                this.waitingForClose = isClosing;
                this.waitingForSave = true;
                this.confirmSelection();
                return;
            } else {
                this.selectionModel.revertModification();
            }

        }
        this.loadAnalysisToSave();
        this.save();
    }

    public void closeAfterProcess() {
        if (this.waitingForClose) {
            this.saveAfterProcess();
            this.parent.closeAnalysisAfterProcess(frmAnalysis);
        }
    }

    public void saveAfterProcess() {
        if (this.waitingForSave) {
            this.loadAnalysisToSave();
            this.save();
            this.waitingForSave = false;
        }
    }

    public boolean isWaitingForClose() {
        return waitingForClose;
    }

    public void editComments() {
        if (this.checkSelectionModel()) {
            this.controllerComment.edit(SystoleApp.getApplication().getMainFrame(), this.reportModel, this.analysis.getPatient());
        }
    }

    public void editConclusions() {
        if (this.checkSelectionModel()) {
            this.controllerConclusion.edit(SystoleApp.getApplication().getMainFrame(), this.reportModel, this.analysis.getPatient());
        }
    }

    public void editIndexComments() {
        if (this.checkSelectionModel()) {
            this.controllerIndex.edit(SystoleApp.getApplication().getMainFrame(), this.reportModel, this.analysis.getPatient());
        }
    }

    public void editBackground() {
        if (this.checkSelectionModel()) {
            this.controllerBackground.edit(SystoleApp.getApplication().getMainFrame(), reportModel, this.analysis.getPatient());
        }
    }

    private boolean checkSelectionModel() {
        if (this.selectionModel.isSelectionEmpty()) {
            this.showMessage("No hay segmentos seleccionados",
                    DialogsMessages.DIALOG_BOX_TITLE, JOptionPane.ERROR_MESSAGE);
            return false;
        }

        if (!this.selectionModel.isConfirmed()) {
            this.showMessage("Debe confirmar los segmentos seleccionados",
                    DialogsMessages.DIALOG_BOX_TITLE, JOptionPane.ERROR_MESSAGE);
            return false;
        }
        return true;
    }

    public boolean isWaitingForSave() {
        return waitingForSave;
    }
}
